package wangjg.coco;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jdt.core.IBuffer;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.ISourceRange;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.Comment;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.Javadoc;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.ui.ISelectionService;
import org.eclipse.ui.internal.Workbench;

public class PDUtil {
	
	public static String getCharset() {
		return getCharset(getCurrentProject());
	}
	
    public static String getCharset(IProject project) {
        // project default encoding first
        if (project != null) {
            try {
                return project.getDefaultCharset();
            } catch (Throwable t) {
                // fails silently
            }
        }
        // default platform fallback
        try {
            return ResourcesPlugin.getWorkspace().getRoot().getDefaultCharset();
        } catch (IllegalStateException ise) {
            // happen when there's no workspace (see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=216817)
            // or when it is shutting down (see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=60687)
            return System.getProperty("file.encoding"); //$NON-NLS-1$
        } catch (CoreException ce) {
            // fails silently and return plugin global encoding if core exception occurs
        }
        return ResourcesPlugin.getEncoding();
    }
	
	private void _test(IFile file) throws JavaModelException{
		ICompilationUnit cu = JavaCore.createCompilationUnitFrom(file);
		IType type = cu.getAllTypes()[0];
		System.out.println("type : "+type.toString());
		System.out.println("type.getPackageFragment().getElementName() : "+type.getPackageFragment().getElementName());
		System.out.println("type.getElementName() : "+type.getElementName());
		IField[] fields = type.getFields();
		for(IField field : fields){
			System.out.println("field.getElementName() : "+field.getElementName());
			ISourceRange range = field.getJavadocRange();
			if (range != null) {
				IBuffer buffer1 = cu.getBuffer();
				System.out.println("f pos : "+range.getOffset() + "  " + range.getLength());
				System.out.println("f doc range : "+buffer1.getText(range.getOffset(),range.getLength()));
			}
		}
	}
	public static void _testAST(File file) throws IOException{
		char[] cbuf = new char[1024*10];
		new FileReader(file).read(cbuf);
		
		ASTParser astParser = ASTParser.newParser(AST.JLS3);
		astParser.setKind(ASTParser.K_COMPILATION_UNIT);
		astParser.setSource(cbuf);
		CompilationUnit unit = (CompilationUnit) astParser.createAST(null);
		TypeDeclaration type = (TypeDeclaration) unit.types().get(0);
		MethodDeclaration[] methods = type.getMethods();
		for (int i = 0; i < methods.length; i++) {
			MethodDeclaration method = methods[i];
			Javadoc doc = method.getJavadoc();
			if (doc != null) {
				foreach(doc.tags());
			}
		}
		System.out.println("----------------------------------------------");
		for(Object c:unit.getCommentList()){
			Comment comment = (Comment)c;
			System.out.println(new String(cbuf,comment.getStartPosition(),comment.getLength()));	
		}
	}
	
	public static void foreach(Iterable iterable){
		for(Object obj:iterable){
			if(obj instanceof Iterable){
				foreach((Iterable) obj);
			}else{
				System.out.println(obj.getClass().getSimpleName()+","+obj);
			}
		}
	}
	
	public static IProject getCurrentProject() {
        ISelectionService selectionService = Workbench.getInstance().getActiveWorkbenchWindow().getSelectionService();    
        ISelection selection = selectionService.getSelection();
        return getProject(selection);
	}
	
	public static IProject getProject(ISelection selection) {
		IProject project = null;
		if (selection instanceof IStructuredSelection) {
			Object element = ((IStructuredSelection) selection).getFirstElement();
			if (element instanceof IResource) {
				project = ((IResource) element).getProject();
			} else if (element instanceof IJavaElement) {
				IJavaProject jProject = ((IJavaElement) element).getJavaProject();
				project = jProject.getProject();
			}
		}
		return project;
	}
	
	public static IJavaProject getJavaProject(Object element) {
		IJavaProject jproject = null;
		if (element instanceof IJavaElement) {
			jproject = ((IJavaElement) element).getJavaProject();
		}else if (element instanceof IResource) {
			IProject project = ((IResource) element).getProject();
			jproject = JavaCore.create(project);
		}
		return jproject;
	}
	
	public static List<IPath> getClasspath(IJavaProject jproject){
		List<IPath> list = new ArrayList<IPath>();
		try {
			list.add(jproject.getOutputLocation());
		} catch (JavaModelException e1) {
			e1.printStackTrace();
		}
		try {
			IClasspathEntry[] cps = jproject.getResolvedClasspath(true);
			for(IClasspathEntry cp:cps){
				if(cp.getEntryKind()==IClasspathEntry.CPE_SOURCE && cp.getOutputLocation()!=null){
					list.add(cp.getOutputLocation());
				}else if(cp.getEntryKind()==IClasspathEntry.CPE_LIBRARY){
					list.add(cp.getPath());
				}else if(cp.getEntryKind()==IClasspathEntry.CPE_VARIABLE){
					list.add(cp.getPath());
				}
			}
		} catch (JavaModelException e) {
			e.printStackTrace();
		}
		return list;
	}
	
	public static List<String> getSourceRoots(IJavaProject jproject){
		List<IPath> pathList = new ArrayList<IPath>();
		try {
			IClasspathEntry[] cps = jproject.getResolvedClasspath(true);
			for(IClasspathEntry cp:cps){
				if(cp.getEntryKind()==IClasspathEntry.CPE_SOURCE){
					pathList.add(cp.getPath());
				}
			}
		} catch (JavaModelException e) {
			e.printStackTrace();
		}
		
		File parent = jproject.getProject().getLocation().toFile();
		List<String> fileList = new ArrayList<String>();
		for(IPath path : pathList){
			String subfile = path.toFile().getPath();
			subfile=subfile.substring(subfile.indexOf(File.separatorChar,1));
			File file = new File(parent, subfile);
			fileList.add(file.getPath());
		}
		
		return fileList;
	}
	
	public static FileClassLoader getClassLoader(IJavaProject jproject){
		File parent=jproject.getProject().getLocation().toFile();
		List<IPath> pathList = getClasspath(jproject);
		List<File> fileList = new ArrayList<File>();
		for(IPath path:pathList){
			String subfile = path.toFile().getPath();
			subfile=subfile.substring(subfile.indexOf(File.separatorChar,1));
			File file = new File(parent, subfile);
			fileList.add(file);
		}
		FileClassLoader classLoader = new FileClassLoader(fileList);
		return classLoader;
	}
	
	public static class FileClassLoader extends URLClassLoader{
		
		public FileClassLoader(List<File> fileList) {
			super(getUrls(fileList), PDUtil.class.getClassLoader());
		}
		
		public Class findClass(String name)throws ClassNotFoundException{
			Class cls = super.findClass(name);
			return cls;
		}

		private static URL[] getUrls(List<File> fileList){
			URL[] urls = new URL[fileList.size()];
			for(int i=0;i<fileList.size();i++){
				try {
					urls[i] = fileList.get(i).toURI().toURL();
				} catch (MalformedURLException e) {
					e.printStackTrace();
				}
			}
			return urls;
		}
	}
}
